/*
 *  Openmysee
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
				 
#include <db.h>
#include "echo.h"

#define MAGIC_TIME	1.3

DB *USERDB;

int
db_init (char *home, char *database)
{
	DB_ENV *dbenv = NULL;
	DB_TXN *txnp = NULL;
	int flags, ret;
	int cachesize = 1000 * 65536;
//      struct stat st_buf;
	DB *dbp = NULL;

//      if (stat (database, &st_buf) < 0 || (!S_ISREG (st_buf.st_mode)))
//              return -1;

	if ((ret = db_env_create (&dbenv, 0)) != 0)
	{
		dbenv->err (dbenv, ret, "db_env_create");
		return -1;
	}
	dbenv->set_errfile (dbenv, stderr);
//      dbenv->set_errpfx (dbenv, prefix);
	(void) dbenv->set_cachesize (dbenv, 0,
				     cachesize ==
				     0 ? 50 * 1024 *
				     1024 : (u_int32_t) cachesize, 0);

	flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK;
	if ((ret = dbenv->open (dbenv, home, flags, 0)) != 0)
	{
		dbenv->err (dbenv, ret, "DB_ENV->open: %s", home);
		(void) dbenv->close (dbenv, 0);
		return -1;
	}
	/* Create and initialize database object, open the database. */
	if ((ret = db_create (&dbp, dbenv, 0)) != 0)
	{
		return -1;
	}
	dbp->set_errfile (dbp, stderr);
//      dbp->set_errpfx (dbp, progname);
	if ((ret = dbp->set_pagesize (dbp, 65536)) != 0)
	{
		dbp->err (dbp, ret, "set_pagesize");
		goto err1;
	}
	if ((ret = dbenv->txn_begin (dbenv, NULL, &txnp, 0)) != 0)
		goto err1;

	if ((ret =
	     dbp->open (dbp, txnp, database, NULL, DB_BTREE, DB_CREATE,
			0664)) != 0)
	{
		dbp->err (dbp, ret, "%s: open", database);
		goto err1;
	}

	if (txnp != NULL)
		ret = txnp->commit (txnp, 0);
	txnp = NULL;
	if (ret != 0)
		goto err1;
	USERDB = dbp;
	return 0;
      err1:
	if (txnp != NULL)
		(void) txnp->abort (txnp);
	(void) dbp->close (dbp, 0);
	return (1);
}

int
isAllowed (int id, char *md5, char *cname, float bitrate,
	   float *limitedbitrate, int *issave)
{
	DB *dbp;
	DB_TXN *txnp = NULL;
	char *p;
	DBT key, data;
	int ret;

	dbp = USERDB;
	memset (&key, 0, sizeof (key));
	key.data = &id;
	key.size = sizeof (id);
	memset (&data, 0, sizeof (data));
	dbp->dbenv->txn_begin (dbp->dbenv, NULL, &txnp, 0);
	if ((ret = dbp->get (dbp, txnp, &key, &data, 0)) != 0)
	{
		dbp->err (dbp, ret, "DB->get");
		ret = -ERR_NO_SUCH_PEER;
		goto err;
	}
	if (data.size == 0 || (p = data.data) == NULL)
	{
		ret = -ERR_NO_SUCH_PEER;
		goto err;
	}
	if (strncmp (md5, p, MD5_LEN) != 0)
	{
		ret = -ERR_AUTHORIZATION;
		goto err;
	}
	p += MD5_LEN;
	if (strcmp (p, cname) != 0)
	{
		ret = -ERR_AUTHORIZATION;
		goto err;
	}
	p += strlen (cname) + 1;
	*limitedbitrate = (*(float *) p) * MAGIC_TIME;
	p += sizeof (float);
	*issave = *(int *)p;
	if (*limitedbitrate < bitrate)
	{
		ret = -ERR_EXCEED_BITRATE;
		goto err;
	}
	if (txnp != NULL)
		ret = txnp->commit (txnp, 0);
	else ret = 0;
//	if (data.data)
//		free (data.data);

	return (ret);

      err:if (txnp != NULL)
		(void) txnp->abort (txnp);
//	  if (data.data) free (data.data);
	return ret;
}

int
db_list ()
{
	DB *dbp;
	DBC *dbcp;
	DBT key, data;
	DB_TXN *txnp;
	int ret;
	char *md5pass;
	char *cname;
	float bitrate;
	int issave;

	dbp = USERDB;
	memset (&key, 0, sizeof (key));
	memset (&data, 0, sizeof (data));
	dbp->dbenv->txn_begin (dbp->dbenv, NULL, &txnp, 0);
	dbp->cursor (dbp, txnp, &dbcp, 0);

	while ((ret = dbcp->c_get (dbcp, &key, &data, DB_NEXT)) == 0)
	{
		md5pass = data.data;
		cname = md5pass + MD5_LEN;
		bitrate = *(float *) (cname + strlen (cname) + 1);
		issave = *(int *) (cname + strlen (cname) + 1 + sizeof (float));
		printf ("%d length %d:%.32s,%s,%f,%d\n", *(int *) key.data,
			data.size, md5pass, cname, bitrate, issave);
//              if (stat (data.data + 2 * sizeof (int), &st_buf) < 0
//                  || (!S_ISREG (st_buf.st_mode)))
//                      ret = dbp->del (dbp, NULL, &key, 0);
//		if (key.data)
//			free (key.data);
//		if (data.data)
//			free (data.data);
	}
	dbcp->c_close (dbcp);
	if (txnp)
		txnp->commit (txnp, 0);

	return (0);
}

int
db_add (int userid, char *pass, char *cname, float limited, int issave)
{
	DB *dbp;
	DBT key, data;
	DB_TXN *txnp;
	char *p;
	int ret, cnamelen;
	/*
	 * Insert records into the database, where the key is the user
	 * input and the data is the user input in reverse order.
	 */
	dbp = USERDB;
	cnamelen = strlen (cname);
	memset (&key, 0, sizeof (DBT));
	memset (&data, 0, sizeof (DBT));
	key.data = &userid;
	key.size = sizeof (int);
	data.size = MD5_LEN + cnamelen + 1 + sizeof (float) + sizeof(int);
	p = malloc (data.size);
	assert (p);
	data.data = p;
	memcpy (p, pass, MD5_LEN);
	p += MD5_LEN;
	memcpy (p, cname, cnamelen + 1);
	p += cnamelen + 1;
	*(float *) p = limited;
	p += sizeof (float);
	*(int *) p = issave;

	if ((ret = dbp->dbenv->txn_begin (dbp->dbenv, NULL, &txnp, 0)) != 0)
		goto err;
	if ((ret = dbp->put (dbp, txnp, &key, &data, 0)) != 0)
	{
		dbp->err (dbp, ret, "DB->put");
		goto err;
	}
	if (txnp != NULL)
		ret = txnp->commit (txnp, 0);
	else ret = 0;

	if (data.data) free (data.data);
	return (ret);

      err:if (txnp != NULL)
		(void) txnp->abort (txnp);
	if (data.data) free (data.data);
	return -1;
}

int
db_del (int userid)
{
	DB *dbp;
	DBT key, data;
	DB_TXN *txnp;
	int ret;
	/*
	 * Insert records into the database, where the key is the user
	 * input and the data is the user input in reverse order.
	 */
	dbp = USERDB;
	memset (&key, 0, sizeof (DBT));
	memset (&data, 0, sizeof (DBT));
	key.data = &userid;
	key.size = sizeof (int);
	if ((ret = dbp->dbenv->txn_begin (dbp->dbenv, NULL, &txnp, 0)) != 0)
		goto err;
	if ((ret = dbp->del (dbp, txnp, &key, 0)) != 0)
	{
		dbp->err (dbp, ret, "DB->put");
		goto err;
	}
	if (txnp != NULL)
		ret = txnp->commit (txnp, 0);
	else ret = 0;

	return (ret);

      err:if (txnp != NULL)
		(void) txnp->abort (txnp);
	return -1;
}

int db_end ()
{
	if (USERDB) USERDB->close (USERDB, 0);
	return 0;
}
